[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern SafeFindHandle FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FindClose(SafeHandle hFindFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool FindNextFile(SafeHandle hFindFile, out WIN32_FIND_DATA lpFindFileData);
internal sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid
{
// Methods
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
internal SafeFindHandle()
: base(true)
{
}
public SafeFindHandle(IntPtr preExistingHandle, bool ownsHandle) : base(ownsHandle)
{
base.SetHandle(preExistingHandle);
}
protected override bool ReleaseHandle()
{
if (!(IsInvalid || IsClosed))
{
return FindClose(this);
}
return (IsInvalid || IsClosed);
}
protected override void Dispose(bool disposing)
{
if (!(IsInvalid || IsClosed))
{
FindClose(this);
}
base.Dispose(disposing);
}
}
private long RecurseDirectory(string directory, int level, out int files, out int folders) {
IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
long size = 0;
files = 0;
folders = 0;
Kernel32.WIN32_FIND_DATA findData;
// please note that the following line won't work if you try this on a network folder, like \\Machine\C$
// simply remove the \\?\ part in this case or use \\?\UNC\ prefix
using(SafeFindHandle findHandle = Kernel32.FindFirstFile(@"\\?\" + directory + @"\*", out findData))
{
if (!findHandle.IsInvalid) {
do {
if ((findData.dwFileAttributes & FileAttributes.Directory) != 0) {
if (findData.cFileName != "." && findData.cFileName != "..") {
folders++;
int subfiles, subfolders;
string subdirectory = directory + (directory.EndsWith(@"\") ? "" : @"\") +
findData.cFileName;
if (level != 0) // allows -1 to do complete search.
{
size += RecurseDirectory(subdirectory, level - 1, out subfiles, out subfolders);
folders += subfolders;
files += subfiles;
}
}
}
else {
// File
files++;
size += (long)findData.nFileSizeLow + (long)findData.nFileSizeHigh * 4294967296;
}
}
while (Kernel32.FindNextFile(findHandle, out findData));
}
}
return size;
}